﻿using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Linq;

namespace SharePointUtilitiesForDevelopers.Mapper
{
    /// <summary>
    /// Defines the signature for a method that maps a
    /// <see cref="XElement"/> to the specified domain object type.
    /// </summary>
    public delegate TTo MapElementToDomainObject<TTo>(XElement from);

    /// <summary>
    /// A helper class that provides methods for mapping xml service response to domain objects.
    /// </summary>
    internal static class SharePointMapper
    {

        /// <summary>
        /// Maps the xml response from a SharePoint web service call to a list of domain objects.
        /// </summary>
        /// <typeparam name="TTo">The domain object type.</typeparam>
        /// <param name="mapElementToDomainObject">The method that maps the xml response to the domain object.</param>
        /// <param name="whereCondition">The where condition to select elements in the xml response.</param>
        /// <param name="xmlResponse">The xml response.</param>
        /// <returns>A list of domain objects.</returns>
        internal static IEnumerable<TTo> MapResponseToList<TTo>(
            MapElementToDomainObject<TTo> mapElementToDomainObject,
            Func<XElement, bool> whereCondition,
            XElement xmlResponse)
        {
            // Select the elements to transform (using where condition) and map the element
            //  to a domain object
            var objects = (from XElement element in xmlResponse.DescendantsAndSelf()
                           where whereCondition(element)
                           select
                               mapElementToDomainObject(element)).ToList();

            return objects;
        }

        /// <summary>
        /// Maps the xml response from a SharePoint web service call to a single domain objects.
        /// </summary>
        /// <typeparam name="TTo">The domain object type.</typeparam>
        /// <param name="mapElementToDomainObject">The method that maps the xml response to the domain object.</param>
        /// <param name="whereCondition">The where condition to select elements in the xml response.</param>
        /// <param name="xmlResponse">The xml response.</param>
        /// <returns>A domain objects.</returns>
        internal static TTo MapResponseToObject<TTo>(
            MapElementToDomainObject<TTo> mapElementToDomainObject,
            Func<XElement, bool> whereCondition,
            XElement xmlResponse)
        {
            // Map to a list, and select a single or default
            return MapResponseToList(
                mapElementToDomainObject,
                whereCondition,
                xmlResponse).SingleOrDefault();
        }

    }
}